home *** CD-ROM | disk | FTP | other *** search
- /*
- File: TAssistant.cp
-
- Contains: Base class implementing an assistant
-
- Written by: Arno Gourdol
-
- Copyright: © 1996 by Apple Computer, Inc., all rights reserved.
-
- */
-
- #include "TAssistant.h"
- #include "assert.h"
-
- #include <Resources.h>
- #include <Sound.h>
-
-
-
- // --------------------------------------------------------------------
- // TAssistant
- // --------------------------------------------------------------------
-
- TAssistant::TAssistant(SInt16 firstPane,
- SInt16 lastPane,
- TApplication* application) :
- CMultiDialog(kCommonPane, kLastCommonItem, kSmallFont),
- fShowDetails(false),
- fFirstPane(firstPane),
- fLastPane(lastPane),
- fApplication(application),
- fHistoryIndex(0)
- {
- // Initialize the history stack
- fHistory[0] = fFirstPane;
-
- // Display the first pane
- SetDialogPane(fFirstPane);
- }
-
-
-
- // --------------------------------------------------------------------
- // ~TAssistant
- // --------------------------------------------------------------------
-
- TAssistant::~TAssistant()
- {
- }
-
-
-
- // --------------------------------------------------------------------
- // CloseRequested
- // --------------------------------------------------------------------
- // Hook function called to confirm that closing the window is OK.
-
- Boolean TAssistant::CloseRequested(void)
- {
- if (fApplication != NULL)
- {
- // If an application was specified at the object creation,
- // ask the application to quit...
- return fApplication->QuitRequested();
- }
- else
- {
- //... otherwise display a confirmation alert
- SInt16 itemHit = StopAlert(kQuitConfirmationDialog, NULL);
-
- return (itemHit == 1);
- }
- }
-
-
-
- // --------------------------------------------------------------------
- // Close
- // --------------------------------------------------------------------
- // Hook function called when the user closes the dialog
- // In our case, we close the dialog and quit the application
- // if we are a stand-alone assistant (i.e. we're our own app <=>
- // fApplication != NULL)
-
- void TAssistant::Close(void)
- {
- CMultiDialog::Close();
-
- if (fApplication != NULL)
- {
- fApplication->Quit();
- }
- }
-
-
-
- // --------------------------------------------------------------------
- // FindNextPane
- // --------------------------------------------------------------------
- // Decides what the next pane should be.
- // Calls NextPane() and SkipPane() to find out.
- // Returns 0 if no more panes
-
-
- SInt16 TAssistant::FindNextPane(SInt16 currentPane)
- {
- assert(currentPane != kConclusionPane &&
- currentPane != kDetailsPane);
-
- SInt16 nextPane = NextPane(currentPane);
-
- // Look for a pane that doesn't have to be skipped
- while (nextPane != 0 && SkipPane(nextPane))
- {
- nextPane = NextPane(nextPane);
- };
-
- // If no more pane, go to the appropriate
- // conclusion pane
- if (nextPane == 0)
- {
- if (fShowDetails)
- nextPane = kDetailsPane;
- else
- nextPane = kConclusionPane;
- }
-
- return nextPane;
- }
-
-
-
- // --------------------------------------------------------------------
- // NextPane
- // --------------------------------------------------------------------
- // Function called to query the ID of the next pane.
- // Returns 0 if no more panes
- // Override this function if you need to present panes in non-sequential
- // order or if you want to skip a long sub-interview.
-
- SInt16 TAssistant::NextPane(SInt16 currentPane)
- {
- if (currentPane == fLastPane)
- return 0;
- else
- return currentPane + 1;
- }
-
-
-
- // --------------------------------------------------------------------
- // SkipPane
- // --------------------------------------------------------------------
- // Hook function called before displaying a pane.
- // Returns true if the pane must be skipped,
- // false if the panel can be displayed
- // Override to skip portion of an interview based on a user's previous
- // answers or on the environment (no network available, etc...)
-
- Boolean TAssistant::SkipPane(SInt16 pane)
- {
- #pragma unused(pane)
- return false;
- }
-
-
-
- // --------------------------------------------------------------------
- // DrawUserItem
- // --------------------------------------------------------------------
- // Hook function called to draw custom user items
- // We use it to draw the banner and the navigation bar
-
- void TAssistant::DrawUserItem(TDrawContext& drawContext,
- short item,
- const CRect& frame)
- {
- CMultiDialog::DrawUserItem(drawContext, item, frame);
-
- if (item == kBannerBackground)
- {
- DrawBanner(drawContext, frame);
- }
- else if (item == kNavbarBackground)
- {
- DrawNavigationBar(drawContext, frame);
- }
- }
-
-
-
- // --------------------------------------------------------------------
- // DrawBanner
- // --------------------------------------------------------------------
- // Draw the banner containing the panel title
-
- void TAssistant::DrawBanner(TDrawContext& drawContext,
- const CRect& frame)
- {
- enum
- {
- kTopicIndent = 16
- };
-
- {
- PixPatHandle backgroundPattern = GetPixPat(128);
-
- if (backgroundPattern != NULL)
- {
- PenPixPat(backgroundPattern);
- drawContext.FillRect(frame);
- PenNormal();
- DisposePixPat(backgroundPattern);
- }
- }
- // Draw the left and top edges brighter…
- drawContext.SetHighColor(CColor(0xFFFF));
- drawContext.MovePenTo(frame.LeftBottom());
- drawContext.StrokeLine(frame.LeftTop());
- drawContext.StrokeLine(CPoint(frame.Right() - 1, frame.Top()));
-
- // Draw the right and bottom edges darker…
- if ((drawContext.GetDepth() >= 8) ||
- (!drawContext.IsColor() && drawContext.GetDepth() == 4))
- drawContext.SetHighColor(CColor(0xAAAA));
- else
- drawContext.SetHighColor(CColor(0));
-
- drawContext.MovePenTo(
- CPoint(frame.Right() - 1, frame.Bottom()));
- drawContext.StrokeLine(frame.LeftBottom());
-
- // Position the line of text and draw it…
- // ??? This will only draw one line of text.
- // Make sure all text fits!
- {
- short saveStyle = fDialogFont.GetStyle();
- // ??? Not international friendly
- fDialogFont.SetStyle(bold);
-
- CRect textBox;
- if (TApplication::gApplication->fEnvironment.IsSystemScriptRTL())
- {
- textBox.SetLeft(frame.Left() + 4);
- textBox.SetRight(frame.Right() - kTopicIndent);
- }
- else
- {
- textBox.SetLeft(frame.Left() + kTopicIndent);
- textBox.SetRight(frame.Right() - 4);
- }
- textBox.SetTop(frame.Top() +
- (frame.Height() - fDialogFont.GetLineHeight()) / 2);
- textBox.SetBottom(textBox.Top() + fDialogFont.GetLineHeight());
-
- Str255 paneTitle;
- BlockMoveData(fPaneTitle, paneTitle, sizeof(Str255));
- fDialogFont.TruncString(frame.Width() - kTopicIndent, paneTitle);
- drawContext.SetHighColor(CColor(0));
- fDialogFont.DrawText(paneTitle, textBox);
-
- fDialogFont.SetStyle(saveStyle);
- }
- }
-
-
-
- // --------------------------------------------------------------------
- // DrawNavigationBar
- // --------------------------------------------------------------------
- // Draw the navigation bar
-
- void TAssistant::DrawNavigationBar(TDrawContext& drawContext,
- const CRect& frame)
- {
- drawContext.SetHighColor(CColor(0xDDDD));
- // Calculate the background region
- RgnHandle backgroundRgn = NewRgn();
-
- // We need to punch holes in the region of the nav bar...
-
- // Iterate over all the controls intersecting with the nav bar
- OpenRgn();
- drawContext.StrokeRect(frame);
-
- ControlRef control = GetControlListFromWindow(GetWindowRef());
- while (control != NULL)
- {
- CRect controlRect((**control).contrlRect);
- // Substract the control's rectangle from the fill area
- if (controlRect.Intersects(frame))
- drawContext.StrokeRect(controlRect);
- control = (**control).nextControl;
- }
- CloseRgn(backgroundRgn);
-
- // Draw the background of the nav bar with holes
- drawContext.FillRegion(backgroundRgn);
-
- // Draw black separator line
- drawContext.SetHighColor(CColor(0));
- drawContext.MovePenTo(
- CPoint(frame.Left(), frame.Top()));
- drawContext.StrokeLine(
- CPoint(frame.Right(), frame.Top()));
-
- // Draw shadow
- drawContext.SetHighColor(CColor(0xAAAA));
- drawContext.MovePenTo(
- CPoint(frame.Left() + 1, frame.Bottom() - 1));
- drawContext.StrokeLine(
- CPoint(frame.Right() - 1, frame.Bottom() - 1));
- drawContext.StrokeLine(
- CPoint(frame.Right() - 1, frame.Top() + 2));
-
- // Draw hilite
- drawContext.SetHighColor(CColor(0xFFFF));
- drawContext.MovePenTo(
- CPoint(frame.Left(), frame.Bottom() - 2));
- drawContext.StrokeLine(
- CPoint(frame.Left(), frame.Top() + 1));
- drawContext.StrokeLine(
- CPoint(frame.Right() - 2, frame.Top() + 1));
-
- // Draw the panel number
- {
- short saveStyle = fDialogFont.GetStyle();
- // ??? Not international friendly
- fDialogFont.SetStyle(bold);
-
- CRect textBox = GetItemRect(kPaneNumber);
-
- Str255 paneNumber;
- ::NumToString(fHistoryIndex + 1, paneNumber);
- drawContext.SetHighColor(CColor(0));
- fDialogFont.DrawText(paneNumber, textBox);
-
- fDialogFont.SetStyle(saveStyle);
- }
-
- }
-
-
-
- // --------------------------------------------------------------------
- // FilterKey
- // --------------------------------------------------------------------
- // Hook function called when a key is pressed.
- // Return true if the key was handled.
- // We use it to handle keyboard navigation of the assistant:
- // return/enter => next field or next pane
- // command-arrows => next or previous pane
-
- Boolean TAssistant::FilterKey(const EventRecord& event, UInt16 key)
- {
- #pragma unused(event)
-
- Boolean result = true;
-
- if (key == keyReturn || key == keyEnter)
- {
- if (GetDialogPane() == kDetailsPane ||
- GetDialogPane() == kConclusionPane)
- {
- FlashButton(kGoAheadButton);
- GoAhead();
- Close();
- }
- else
- {
- Boolean isShiftKeyDown = ((event.modifiers & shiftKey) != 0);
-
- // If the shift key is pressed, reverse direction
- if (isShiftKeyDown)
- {
- short prevTextField = PreviousTextField();
- if (prevTextField > 0)
- {
- SelectItemText(prevTextField);
- }
- else
- {
- GoToPreviousPane();
- // Select the last text field if we are going backwards
- {
- short lastTextField = LastTextField();
- if (lastTextField > 0)
- SelectItemText(lastTextField);
- }
- }
- }
- else
- {
- short nextTextField = NextTextField();
- if (nextTextField > 0)
- {
- SelectItemText(nextTextField);
- }
- else
- {
- GoToNextPane();
- }
- }
- }
- result = true;
- }
- else if (key == keyEscape)
- {
- if (CloseRequested())
- Close();
- }
- else if (key == keyHome)
- {
- GoToPane(fFirstPane);
- }
- else if (key == keyEnd)
- {
- if (fShowDetails)
- GoToPane(kDetailsPane);
- else
- GoToPane(kConclusionPane);
- }
- else if (key == keyPageUp)
- {
- GoToPreviousPane();
- }
- else if (key == keyPageDown)
- {
- GoToNextPane();
- }
- else if (key == keyArrowLeft && (event.modifiers & cmdKey))
- {
- GoToPreviousPane();
- }
- else if (key == keyArrowRight && (event.modifiers & cmdKey))
- {
- GoToNextPane();
- }
- else
- {
- result = false;
- }
-
- return result;
- }
-
-
-
- // --------------------------------------------------------------------
- // ItemHit
- // --------------------------------------------------------------------
- // Hook function called when an item is selected
-
- void TAssistant::ItemHit(UInt16 pane, short item)
- {
- assert(fHistory[fHistoryIndex] == pane);
-
- if (pane == kConclusionPane || pane == kDetailsPane)
- {
- if (item == kGoAheadButton)
- {
- GoAhead();
- Close();
- }
- else if (item == kCancelButton)
- {
- Close();
- }
- else if (pane == kConclusionPane && item == kShowDetailsButton)
- {
- fHistory[fHistoryIndex] = kDetailsPane;
- fShowDetails = true;
- SetDialogPane(kDetailsPane);
- }
- else if (pane == kDetailsPane && item == kHideDetailsButton)
- {
- fHistory[fHistoryIndex] = kConclusionPane;
- fShowDetails = false;
- SetDialogPane(kConclusionPane);
- }
- }
-
- if (item == kContinueButton)
- {
- GoToNextPane();
- }
- else if (item == kGoBackButton)
- {
- GoToPreviousPane();
- }
-
- CMultiDialog::ItemHit(pane, item);
- }
-
-
-
- // --------------------------------------------------------------------
- // GoToNextPane
- // --------------------------------------------------------------------
- // Go tp the next pane,
- // push the current pane on the history stack
-
- void TAssistant::GoToNextPane(void)
- {
- UInt16 pane = GetDialogPane();
-
- if(pane == kDetailsPane || pane == kConclusionPane)
- {
- // If we are at the last pane, just beep
- SysBeep(0);
- }
- else
- {
- // Find the next pane and push it on the history stack
- fHistory[++fHistoryIndex] = FindNextPane(pane);
- GoToPane(fHistory[fHistoryIndex]);
- }
- }
-
-
-
- // --------------------------------------------------------------------
- // GoToPreviousPane
- // --------------------------------------------------------------------
- // Goes to the previous pane, from the history stack
-
- void TAssistant::GoToPreviousPane(void)
- {
- if (fHistoryIndex == 0)
- {
- // If we are at the first pane, can't go back
- SysBeep(0);
- }
- else
- {
- // Pop the previous pane from the history stack
- GoToPane(fHistory[--fHistoryIndex]);
- }
- }
-
-
-
- // --------------------------------------------------------------------
- // GoToPane
- // --------------------------------------------------------------------
- // Goes directly to a pane.
- // Doesn't affect the history stack
-
- void TAssistant::GoToPane(UInt16 paneID)
- {
- SetDialogPane(paneID);
-
- // The banner and pane number changes with each pane...
- // ... make sure they get updated
- ::InvalRect(GetItemRect(kBannerBackground));
- ::InvalRect(GetItemRect(kPaneNumber));
- }
-
-
-
- // --------------------------------------------------------------------
- // PrepareDialog
- // --------------------------------------------------------------------
- // Hook function called to do any additional preparation to the dialog
- // In our case we enable the appropriate go back and continue buttons
- // and set-up the banner user item, getting the string from the
- // overlapping static text item.
-
- void TAssistant::PrepareDialog(void)
- {
- CMultiDialog::PrepareDialog();
-
- EnableItem(kGoBackButton, GetDialogPane() != fFirstPane);
- EnableItem(kContinueButton, (GetDialogPane() != kConclusionPane)
- && (GetDialogPane() != kDetailsPane));
-
- // Search for a label for the pane
- // The label is a static text string inside the banner (third item)
- {
- CRect bannerRect = GetItemRect(kBannerBackground);
- UInt16 itemCount = CountDITL(GetDialogRef());
-
- // Loop thru the items of the dialog
- for (UInt16 item = 1; item <= itemCount; item++)
- {
- // If the banner's bound countain the bounds of this item
- if (bannerRect.Contains(GetItemRect(item)))
- {
- // ... and this item is a static text
- if (GetItemType(item) == kStaticTextDialogItem)
- {
- // We've found the title of the pane
- GetItemText(item, fPaneTitle);
- HideItem(item);
- }
- }
- }
- }
-
- }
-
-
-
- // --------------------------------------------------------------------
- // GoAhead
- // --------------------------------------------------------------------
- // Function called when the user click the Go Ahead button in the
- // conclusion pane.
- // Time for the assistant to get to work.
-
- void TAssistant::GoAhead(void)
- {
- }
-
-